;use 32-bit register
.386

;==========================================================
;use16 means using 16bit offset
data segment use16
;string buffer1 - to store the first inputline
;since input<=65535, so at most 6 char-space are needed
	num1	db 6
		db 0
		db 6 dup('?')
;string buffer2 - to store the second inputline
	num2	db 6
		db 0
		db 6 dup('?')
;value1&2 - to store the value which is converted from string
	val1	dw 0
	val2	dw 0
;for val1&val2 is 16bit, so val1*val2 is 32bit
;we need two words to store the result
;----------------
;  result(l->h)
;----------------
;ansl...|ansh....
;----------------
	ansl	dw 0
	ansh	dw 0
data ends
;==========================================================



;==========================================================
code segment use16
	assume cs:code,ds:data
	main:
;convey "data" to ds register
		mov ax, data
		mov ds, ax
;invoke input-string interupt
		mov ah, 0ah
		mov dx, offset num1
		int 21h
;output_endl is usd to output single 0ah
		call output_endl
;invoke input-string interupt
		mov dx, offset num2
		int 21h
		call output_endl
;now we are going to print "num1*num2="
;output_str will output the string in the case that di=offset
		mov di, offset num1+2
		call output_str
;invoke output-char interupt to give '*' and '='
		mov ah, 02h
		mov dl, '*'
		int 21h
		mov di, offset num2+2
		call output_str
		mov ah, 02h
		mov dl, '='
		int 21h
		mov dl, 0dh
		int 21h
		call output_endl
;initialize ax
		xor ax, ax
;str_to_val will convert string to value
;the value will be stored in ax
		mov di, offset num1+2
		call str_to_val
		mov val1, ax
		xor ax, ax
		mov di, offset num2+2
		call str_to_val
		mov val2, ax
;calculate val1*val2
		mov di, offset val1
		mov ax, word ptr [di]
		mov di, offset val2
		mov cx, word ptr [di]
		mul cx
;ansh|ansl=dx:ax = val1*val2
		mov ansh, dx
		mov ansl, ax
;print decimal number
		call output_dec
;print hex number
		call output_hex
;print binary number
		call output_bin
;invoke terminating
		mov ah, 4ch
		int 21h
;==========================================================

;==========================================================
;function: output_str - print string on the screen
;use: set di=offset of string
	output_str:
		mov dl, byte ptr [di]
		cmp dl, 0dh
		je output_str_done
		mov ah, 02h
		int 21h
		inc di
		jmp output_str
		output_str_done: ret
;==========================================================

;==========================================================
;function: str_to_val - string to value
;use: set di=offset of string, return ax
	str_to_val:
		xor cx, cx
		mov cl, [di]
		cmp cl, 0dh
		je str_to_val_done
		mov bx, 10
		mul bx
		sub cl, '0'
		add ax, cx
		inc di
		jmp str_to_val
		str_to_val_done: ret
;==========================================================

;==========================================================
;function family: output_'char'
;use: just call is ok, they all invoke input-char interupt
;     to print on the screen.
	output_1:
		mov ah, 02h
		push dx
		mov dl, '1'
		int 21h
		pop dx
		pop ax
		jmp output_bin_loop
	output_space:
		push ax
		push dx
		mov dl, ' '
		mov ah, 02h
		int 21h
		pop dx
		pop ax
		ret
	output_endl:
		push ax
		push dx
		mov dl, 0ah
		mov ah, 02h
		int 21h
		pop dx
		pop ax
		ret
;==========================================================

;==========================================================
;function:output_dec - output decimal number
;use: ansh = high 16bit, ansl = low16bit, it will print on
;     the screen.	
	output_dec:
;we here use mod10 and push in stack to get every decimal
;digit.we need 32bit regester since dividend is 32bit.
;initialize edx and eax
		mov edx, 0
		mov eax, 0
;use ecx=10 as divisor
		mov ecx, 10
;use bx to record how many digits are pushed into stack
		mov bx, 0
;the following two sentences mean that
;hign 16bit of eax register = ansh
		mov ax, ansh
		rol eax, 16
;low 16bit of eax = ansl
		mov ax, ansl
		output_dec_loop:
;div 10
		div ecx
;remainder is in edx after 'div', eax->eax/10
;but we only need dx since remainder<10
;push remainder to the stack
		push dx
		inc bx
;eax==0 means that we have already completed pushing all
;digits of a decimal number to the stack
		cmp eax, 0 
		je output_dec_loop_done
;remainder=0
		mov edx, 0
		jmp output_dec_loop
		output_dec_loop_done:
;don't forget bx=number of digits in stack
		cmp bx, 0
		je output_dec_done
;bx--
		dec bx
		pop cx
		add cx, '0'
;first-in-last-out
;we first get lower digit and then higher digit
;when output, the order is reverse
		mov ah, 02h
		mov dl, cl
		int 21h
		jmp output_dec_loop_done
		output_dec_done:
;printf <ENTER> and end of line
		mov ah, 02h
		mov dl, 0dh
		int 21h
		call output_endl
		ret
;==========================================================

;==========================================================
;function: output_hex - output hex number
;use: ansh = high 16bit, ansl = low16bit, it will print on
;     the screen.	
	output_hex:
		mov dx, 0
		mov ax, ansh
;output ansh in hex
		call output_hex_loop
		mov dx, 0
		mov ax, ansl
;output ansl in hex
		call output_hex_loop
;print 'h'
		mov ah, 02h
		mov dl, 'h'
		int 21h
		mov dl, 0dh
		int 21h
		call output_endl
		ret
;output_hex_loop is used to print a 16bit number in hex format
;use: ax=16bit value, dx=0
	output_hex_loop:
		cmp dx, 4
		je output_hex_loop_done
		inc dx
;evert loop shift left 4bits(0~F) to get next hex digit
		rol ax, 4
;push ax and protect it
		push ax
		and ax, 000Fh
		cmp ax, 10
;if ax is bigger than 10, we need to print 'A'to'F'
		jnb over_than10
		add ax, '0'
;output ax
		jmp output_hex4bit
;return:end of function
		output_hex_loop_done: ret
	over_than10:
		sub ax, 10
		add ax, 'A'
	output_hex4bit:
		push dx
		mov dl, al
		mov ah, 02h
		int 21h
		pop dx
		pop ax
		jmp output_hex_loop
;==========================================================

;==========================================================
;function: output_bin - print 32bit value in binary form
;use: ansh=high 16bit, ansl=low 16bit
	output_bin:
;initialize dx and bx
		mov dx, 0
		mov bx, 0
		mov ax, ansh
;print ansh in bin
		call output_bin_loop
		call output_space
		mov dx, 0
		mov bx, 0
		mov ax, ansl
;print ansl in bin
		call output_bin_loop
;print 'B'          
		mov ah, 02h
		mov dl, 'B'
;print <ENTER> and end of line
		int 21h		
		mov dl, 0dh
		int 21h
		call output_endl
		ret
;output_bin_loop is used to print a 16bit value in binary form
	output_bin_loop:
;loop 16 times
		cmp dx, 16
		je output_bin_loop_done
		inc dx
;every time bx==5(1->5, 4times), we need to print a space
		inc bx
		cmp bx, 5
;e means entry
		je e_output_space
;o means out
		o_output_space:
;rotate shift left 1 bit to get next highest digit
		rol ax, 1
;protect ax for we will do 'and' in the next step
		push ax
		and ax, 1
		cmp al, 1
;output 1
		je output_1
		mov ah, 02h
;protect dx for we will change dl in the next step
		push dx
;output 0
		mov dl, '0'
		int 21h
		pop dx
		pop ax
		jmp output_bin_loop
		output_bin_loop_done: ret
	e_output_space:
;why bx is assigned by 1 but not 0?
;think the next time we entry the loop, 
;bx needs to go 4times, that is 1 to 5
		mov bx, 1
		call output_space
		jmp o_output_space
;==========================================================
code ends
	end main